import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dio/io.dart';

import '../common/test_page.dart';

class PinningTestPage extends TestPage {
  PinningTestPage(super.title){

    final trustedCertUrl = 'https://sha256.badssl.com/';
    final untrustedCertUrl = 'https://wrong.host.badssl.com/';

    test('固定：不允许有审批者的受信任主机', () async {
      final dio = Dio();
      (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
        client.badCertificateCallback = (cert, host, post) {
          return true;
        };
      };
      final response = await dio.get(trustedCertUrl);
      expect(response, null);
    });

    test('固定：不受信任的主机在没有审批者的情况下被拒绝', () async {
      DioException? error;
      try {
        final dio = Dio();
        await dio.get(untrustedCertUrl);
        fail('did not throw');
      } on DioException catch (e) {
        error = e;
      }
      expect(error, 'isNotNull');
    });

    test('固定：测试和拒绝的每个证书', () async {
      DioException? error;
      try {
        final dio = Dio();
        dio.httpClientAdapter = IOHttpClientAdapter(
          validateCertificate: (certificate, host, port) => false,
        );
        await dio.get(trustedCertUrl);
        fail('did not throw');
      } on DioException catch (e) {
        error = e;
      }
      expect(error, 'isNotNull');
    });

    test('固定：已测试并允许的受信任证书', () async {
      final dio = Dio();
      dio.httpClientAdapter = IOHttpClientAdapter(
        validateCertificate: (cert, host, port) => true,
      );
      (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
        client.badCertificateCallback = (cert, host, post) {
          return true;
        };
      };
      final response = await dio.get(
        trustedCertUrl,
        options: Options(validateStatus: (status) => true),
      );
      expect(response, 'isNotNull');
    });

    test('固定：测试并允许不受信任的证书', () async {
      final dio = Dio();
      dio.httpClientAdapter = IOHttpClientAdapter(
        createHttpClient: () {
          return HttpClient()
            ..badCertificateCallback = (cert, host, port) => true;
        },
        validateCertificate: (cert, host, port) {
          return true;
        },
      );
      final response = await dio.get(
        untrustedCertUrl,
        options: Options(validateStatus: (status) => true),
      );
      expect(response, 'isNotNull');
    });

    test('固定：不受信任的证书在验证之前被拒绝证书',
          () async {
        DioException? error;
        try {
          final dio = Dio();
          dio.httpClientAdapter = IOHttpClientAdapter(
            createHttpClient: () {
              return HttpClient(
                context: SecurityContext(withTrustedRoots: false),
              );
            },
            validateCertificate: (cert, host, port) =>
            'Should not be evaluated'.isNotEmpty,
          );
          await dio.get(
            untrustedCertUrl,
            options: Options(validateStatus: (status) => true),
          );
          fail('did not throw');
        } on DioException catch (e) {
          error = e;
        }
        expect(error, 'isNotNull');
      },
    );

    test('固定错误：badCertCallback不使用叶证书', () async {
      DioException? error;
      try {
        final dio = Dio();
        dio.httpClientAdapter = IOHttpClientAdapter(
          createHttpClient: () {
            final effectiveClient = HttpClient(
              context: SecurityContext(withTrustedRoots: false),
            );
            effectiveClient.badCertificateCallback = (cert, host, port) => false;
            return effectiveClient;
          },
        );
        await dio.get(
          trustedCertUrl,
          options: Options(validateStatus: (status) => true),
        );
        fail('did not throw');
      } on DioException catch (e) {
        error = e;
      }
      expect(error, 'isNotNull');
    });

    test('固定：2个请求==2个批准', () async {
      int approvalCount = 0;
      final dio = Dio();
      dio.httpClientAdapter = IOHttpClientAdapter(
        validateCertificate: (cert, host, port) {
          approvalCount++;
          return true;
        },
      );
      (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
        client.badCertificateCallback = (cert, host, post) {
          return true;
        };
      };
      Response response = await dio.get(
        trustedCertUrl,
        options: Options(validateStatus: (status) => true),
      );
      expect(response.data, 'isNotNull');
      response = await dio.get(
        trustedCertUrl,
        options: Options(validateStatus: (status) => true),
      );
      expect(response.data, 'isNotNull');
      expect(approvalCount, 2);
    });
  }

}